/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package uk.ac.cam.ccn.sac.modules.publicmessage;

import java.io.IOException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import org.ccnx.ccn.CCNHandle;
import org.ccnx.ccn.config.ConfigurationException;
import org.ccnx.ccn.config.UserConfiguration;
import org.ccnx.ccn.impl.CCNFlowControl.SaveType;
import org.ccnx.ccn.io.content.CCNStringObject;
import org.ccnx.ccn.io.content.ContentEncodingException;
import org.ccnx.ccn.profiles.security.KeyProfile;
import org.ccnx.ccn.protocol.ContentName;
import org.ccnx.ccn.protocol.MalformedContentNameStringException;
import org.ccnx.ccn.protocol.PublisherPublicKeyDigest;
import uk.ac.cam.ccn.sac.modules.contacts.Contact;
import uk.ac.cam.ccn.sac.net.CCNNet;
import uk.ac.cam.ccn.sac.modules.contacts.CCNSerializableContactObject;

/**
 *
 * @author Thomas
 */
public class TextListener extends Thread{
    protected boolean isRunning=true;
    protected CCNNet net;    
    private ContentName nameSpace;
    
    protected CCNStringObject readString;
    protected CCNHandle textReadHandle = CCNHandle.getHandle();
    protected CCNStringObject writeString;
    protected ContentName textNameSpace;
    protected static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("HH:mm");
    
    
    
    protected static Map<PublisherPublicKeyDigest, Contact> friendlyNames = new HashMap<PublisherPublicKeyDigest, Contact>();
    protected static Map<String, Contact> nameToContact = new HashMap<String, Contact>();
    private CCNStringObject readNameString;
    private CCNStringObject writeNameString;
    
    
    public TextListener(){}
    
    public TextListener(CCNNet net, ContentName nameSpace) throws ConfigurationException, IOException, MalformedContentNameStringException{
        super("TextListener");
        this.net = net;
        this.nameSpace=nameSpace;
        // handle for wirtting text
        CCNHandle tempTextWriteHandle = CCNHandle.open();
        textNameSpace = ContentName.fromURI(nameSpace.toURIString()+"/text/");
        readString = new CCNStringObject(textNameSpace, (String)null, SaveType.RAW, textReadHandle);
        readString.updateInBackground(true);
        
        String introduction = UserConfiguration.userName() + " has entered " + textNameSpace;
        writeString = new CCNStringObject(textNameSpace, introduction, SaveType.RAW, tempTextWriteHandle);
        writeString.save();
        
        String userNameStr = nameSpace.toURIString() + "/members/";
        ContentName friendlyNameNamespace = KeyProfile.keyName(ContentName.fromURI(userNameStr), readString.getContentPublisher());
        System.out.println("FriendlyNames NameSpace is "+friendlyNameNamespace);
        
        //read the string here.....	
        readNameString = new CCNStringObject(friendlyNameNamespace, (String)null, SaveType.RAW, textReadHandle);
        readNameString.updateInBackground(true);

        String publishedNameStr = UserConfiguration.userName();
        System.out.println("adding local friendly name as " + publishedNameStr);
        writeNameString = new CCNStringObject(friendlyNameNamespace, publishedNameStr, SaveType.RAW, tempTextWriteHandle);
        writeNameString.save();
        
        // publish the local contact details
        Contact contact = CCNNet.getInstance().getLocalContact();
        if(contact!=null){
            ContentName contactNameSpace = ContentName.fromURI(friendlyNameNamespace.toURIString()+"/contact/");
            System.out.println("Contact details available at: "+contactNameSpace.toURIString());
            CCNSerializableContactObject readContact = new CCNSerializableContactObject(contactNameSpace, contact, SaveType.RAW, textReadHandle);
            readContact.updateInBackground(true);
            CCNSerializableContactObject writeContact = new CCNSerializableContactObject(contactNameSpace, contact, SaveType.RAW, tempTextWriteHandle);
            writeContact.save();
        }
        // add my name to the list
        addFriendlyName(writeNameString.getContentPublisher(), writeNameString.string());
    }
    
    @Override
    public void run(){
        Timestamp lastUpdate = null;
        do{
            try{
                synchronized(readString) {
                        readString.wait(500);
                }
            }catch(InterruptedException e){}
            try{
                if(readString.isSaved()){
                    Timestamp thisUpdate = readString.getVersion();
                    if(lastUpdate == null || thisUpdate.after(lastUpdate)){
                        lastUpdate=thisUpdate;
                        System.out.println("Got a text update "+thisUpdate);
                        
                        //lookup friendly name to display for this user.....
                        String userFriendlyName = getFriendlyName(readString.getContentPublisher());
                        if(!userFriendlyName.equals("")){
                            showMessage(userFriendlyName, thisUpdate, readString.string());
                        }
                    }
                }
            }catch(Exception e){}
        }while(isRunning);
    }
    
    private void addFriendlyName(PublisherPublicKeyDigest key, String name){
        Contact c = null;
        // we have found a new contact
        if(net!=null){            
            try{
                String userNameStr = nameSpace.toURIString() + "/members/";
                ContentName friendlyNameNamespace = KeyProfile.keyName(ContentName.fromURI(userNameStr), readString.getContentPublisher());
                ContentName contactNameSpace = ContentName.fromURI(friendlyNameNamespace.toURIString()+"/contact/");
                System.out.println("Contact details available at: "+contactNameSpace.toURIString());
                CCNSerializableContactObject readContact = new CCNSerializableContactObject(contactNameSpace, new Contact(), SaveType.RAW, textReadHandle);
                readContact.update(100);
                c = readContact.contact();
            }catch(Exception e){
                System.out.println(e.getMessage());
            }
            // we could not read the contact (probably native chat version)
            if(c==null){
                c = new Contact();
                c.addAttribute(Contact.USER_NAME, name);
            }
            net.newContact(c);
        }
        if(c!=null){
            friendlyNames.put(key, c);
            nameToContact.put(name, c);
        }
    }
    
    private String getFriendlyName(PublisherPublicKeyDigest key) throws MalformedContentNameStringException, IOException{
        if(friendlyNames.containsKey(key))
            return friendlyNames.get(key).getAttribute(Contact.USER_NAME);
        else{
            // not in the map retrieve it from the network
            String userNameStr = nameSpace.toURIString() + "/members/";
            ContentName friendlyNameNamespace = KeyProfile.keyName(ContentName.fromURI(userNameStr), readString.getContentPublisher());
            String temp = friendlyNameNamespace.toURIString();
            System.out.println(temp);
            try {
                readNameString = new CCNStringObject(friendlyNameNamespace, (String)null, SaveType.RAW, textReadHandle);
            }catch (Exception e){}
            // we wait, we could eventually use a call back here
            readNameString.update(100);
            if(readNameString.available()){
                addFriendlyName(readNameString.getContentPublisher(), readNameString.string());
                return readNameString.string();
            }
        }
        return "";
    }
    
    private void showMessage(String name, Timestamp time, String message) throws ContentEncodingException, IOException {
        String msg = "["+name+" "+DATE_FORMAT.format(time)+"] "+message;
        net.showMessage(msg);        
    }
    
    public void sendText(String msg) throws ContentEncodingException, IOException{
        writeString.save(msg);
    }
    
    public void shutdown(){        
        if(readString!=null)
            readString.cancelInterest();
        isRunning = false;
    }
}
